#include "../../config.h"

#include <string.h>

#include "../strfuncs.h"
#include "writer.h"

namespace gpyp {
namespace conf {

namespace {
struct XMLQuote {
  const char  chr;
  const char *rep;
};
/* GMarkupParserは上5つしかエンティティをサポートしていない。 */
XMLQuote _quotes[] = {
  {'&',  "&amp;"},
  {'<',  "&lt;"},
  {'>',  "&gt;"},
  {'\"', "&quot;"},
  {'\'', "&apos;"},
  {'\n', NULL},
  {'\r', NULL},
  {0,    NULL}
};
}

bool Writer::open(const std::string &file_path) {
  if (file_) return false;
  return (file_ = fopen(file_path.c_str(), "w")) != NULL;
}
void Writer::close() {
  if (file_) fclose(file_);
  file_ = NULL;
}

void Writer::indent() {
  for(size_t i = 0; i < depth_; ++i) {
    fwrite("  ", 2, 1, file_);
  }
}
void Writer::write(const Glib::ustring &data, bool escape) {
  if (escape) {
    const char *p = data.c_str(), *l = p;
    for(; *p; ++p) {
      XMLQuote *quote = NULL;
      for(XMLQuote *q = _quotes; q->chr; ++q) {
        if (*p == q->chr) {
          quote = q;
          break;
        }
      }
      if (quote) {
        if (l < p) fwrite(l, 1, p - l, file_);
        if (quote->rep) {
          fwrite(quote->rep, 1, strlen(quote->rep), file_);
        } else {
#define CHR2HEX(HB) ((HB)+((HB)>9?'A'-10:'0'))
          static char buf[6] = {'&', '#', 'x', '0', '0', ';'};
          buf[3] = CHR2HEX((*p >> 4) & 0xf);
          buf[4] = CHR2HEX(*p & 0xf);
          fwrite(buf, 1, sizeof(buf), file_);
#undef CHR2HEX
        }
        l = p + 1;
      }
    }
    if (*l) fwrite(l, 1, strlen(l), file_);
  } else {
    fwrite(data.c_str(), 1, data.bytes(), file_);
  }
}
void Writer::write_attribute(const Glib::ustring &name,
                             const Glib::ustring &value) {
  write(name, true);
  write("=\"");
  write(value, true);
  write("\"");
}
void Writer::new_line() {
  write("\n");
}
void Writer::push() {
  ++depth_;
}
void Writer::pop() {
  --depth_;
}

Writer::Writer() :
  file_ (NULL),
  depth_(0)
{
}
Writer::~Writer() {
  close();
}

}/*conf*/
}/*gpyp*/
